#include "tcp_client.hpp"
#include "../base/logger.h"

namespace easyasio {
namespace net {

TcpClient::TcpClient(asio::io_service& io_service, const std::string& remote_addr, int remote_port)
:   io_service_(io_service), 
    remote_addr_(remote_addr), 
    remote_port_(remote_port),
	conn_(std::make_shared<TcpConnection>(io_service)),
    connect_(false),
    state_(Disconnected),
    retry_(true)
{ }

void TcpClient::asynConnect()
{
    LOG_TRACE("TcpClient::asynConnect");
    assert(state_ == Disconnected);
    setState(Connecting);
    connect_ = true;
    io_service_.dispatch(std::bind(&TcpClient::connectInLoop, shared_from_this()));
}


void TcpClient::stop()
{
    connect_ = false;
    State s = state();
    setState(Disconnected);
    if (s == Connected)
    {
        conn_->shutdown();
        LOG_TRACE("TcpClient::stop conn_->shutdown");
    }
    else if (s == Connecting)
    {
        conn_->forceClose();
        LOG_TRACE("TcpClient::stop conn_->forceClose");
    }
}

void TcpClient::connectInLoop()
{
    if (connect_ && state() == Connecting)
    {
        asio::ip::tcp::resolver resolver(io_service_);
        asio::ip::tcp::resolver::query query(remote_addr_, std::to_string(remote_port_));
        asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

        conn_->socket().async_connect(iterator->endpoint(), 
             std::bind(&TcpClient::handleConnect, shared_from_this(), std::placeholders::_1));
    }
}

void TcpClient::handleConnect(const asio::error_code& error)
{
    if (error)
    {
        LOG_ERROR("TcpClient::handleConnect {}", error.message());
        if (connect_)
        {
            assert(state() == Connecting);
            connectInLoop();
        }
        return;
    }

    LOG_TRACE("TcpClient::handleConnect success!");
    assert(state() == Connecting);
    if (connect_)
    {
        setState(Connected);
        conn_->setConnectionCallback(connectionCallback_);
        conn_->setMessageCallback(messageCallback_);
        conn_->setWriteCompleteCallback(writeCompleteCallback_);
        conn_->start();
    }
    else
    {
        conn_->forceClose();
    }
}

} // easyasio
} // net 